import React,{useReducer, useCallback} from 'react';
import cacheReducer from './cacheReducer';
import CacheContext from './CacheContext';
import * as cacheTypes from './cache-types';

function KeepAliveProvider(props) {
  //cacheStates 存放所有的缓存信息
  //dispatch    派发动作的方法,可以通过派发动作修改缓存信息
  const [cacheStates, dispatch] = useReducer(cacheReducer, {});
  const mount = useCallback(({cacheId, reactElement}) => {
    if (!cacheStates[cacheId]) {
      dispatch({type: cacheTypes.CREATE, payload: {cacheId, reactElement}})
    }else {
      const cacheState = cacheStates[cacheId];
      if (cacheState.status === cacheTypes.DESTROY) {
        const doms = cacheState.doms;
        doms.forEach(dom => dom.parentNode.removeChild(dom));
        dispatch({type: cacheTypes.CREATE, payload: {cacheId, reactElement}})
      }
    }
  }, [cacheStates]);

  const handleScroll = useCallback((cacheId, event) => {
    if(cacheStates[cacheId]){
      const {target} = event;
      const scrolls = cacheStates[cacheId].scrolls;
      scrolls[target] = target.scrollTop;
    }
  },[cacheStates]);

  return (
    <CacheContext.Provider value={{cacheStates, dispatch, mount, handleScroll}}>
      {/** 1 查出要缓存的*/}
      {props.children}
      {/*↑ 上面这里是查出了 有哪些需要缓存 然后放在cacheStates里做个记录（作为我们下面循环的依据），再在循环把这些个需要缓存的缓存起来*/}

      {/** 2 给那些查出要缓存的做代孕,并通知上面再次渲染(这次会真正渲染出内容)*/}
      {
        //把缓存里的虚拟dom变成真实dom
        Object.values(cacheStates).filter(cacheState=>cacheState.status!==cacheTypes.DESTROY).map(({cacheId, reactElement}) => (
          //id={`cache-${cacheId}`} 只是为了方便观看,实际中可以去除
          <div id={`cache-${cacheId}`} key={cacheId} ref={
            dom => {
              const cacheState = cacheStates[cacheId];
              if (dom && (!cacheState.doms || cacheState.status === cacheTypes.DESTROY)) {
                const doms = Array.from(dom.childNodes);
                dispatch({type: cacheTypes.CREATED, payload: {cacheId, doms}}); //这里才是真正缓存了第一次渲染出来的真实dom, 稍后, 在withKeepAlive组件第二次渲染时 会把这里代孕的出来的真实dom 插到我们withKeepAlive的顶级节点下
              }
            }
          }>
            {reactElement}
          </div>
        ))
      }
    </CacheContext.Provider>
  )
}

export default KeepAliveProvider;
